//+------------------------------------------------------------------+
//|                        FilePipe.mqh 管道文件操作类头文件        |
//|                版权所有 2000-2025, MetaQuotes Ltd.              |
//|                        官方网址: https://www.mql5.com            |
//+------------------------------------------------------------------+
#include "File.h"  // 引入通用文件操作基类 CFile 的声明

//+------------------------------------------------------------------+
//| CFilePipe 类                                                     |
//| 功能：MT5 管道式二进制文件操作类，支持“等待数据就绪”的二进制读写 |
//| 继承关系：public CFile（基于通用文件类扩展管道特性）              |
//| 核心特性：                                                      |
//|  1. 自动以二进制模式打开文件，无需额外指定 FILE_BIN 标志          |
//|  2. 提供 Read 前的“数据就绪等待”机制（解决管道/异步文件的读取阻塞问题） |
//|  3. 支持基础数据类型、数组、结构体、枚举、字符串及 CObject 对象的二进制读写 |
//+------------------------------------------------------------------+
class CFilePipe : public CFile
  {
public:
   /**
    * @brief 构造函数：初始化管道文件操作实例
    * @details 调用父类 CFile 构造函数，默认编码为 ANSI，未绑定文件
    */
                     CFilePipe(void);

   /**
    * @brief 析构函数：销毁管道文件操作实例
    * @details 自动调用父类 Close 方法，关闭已打开的文件并释放资源
    */
                    ~CFilePipe(void);

   //--- 管道文件打开接口
   /**
    * @brief 以二进制模式打开管道/文件（自动添加 FILE_BIN 标志）
    * @param file_name [in] 文件/管道路径（如 "//./pipe/MyPipe" 或 "C:\\data.bin"）
    * @param open_flags [in] 打开模式标志（如 FILE_READ 只读、FILE_WRITE 写入、FILE_APPEND 追加，无需包含 FILE_BIN）
    * @return int - 操作结果：成功返回文件句柄（>0），失败返回 INVALID_HANDLE（-1）
    * @note 若已打开其他文件/管道，会先自动关闭旧句柄
    */
   int               Open(const string file_name,const int open_flags);

   //--- 数据就绪等待接口（核心管道特性）
   /**
    * @brief 等待文件/管道中存在指定大小的可读数据
    * @param size [in] 等待的最小数据大小（字节，如 sizeof(int) 表示等待 4 字节数据）
    * @return bool - 等待结果：true 表示数据已就绪（文件大小 >= size），false 表示等待失败（句柄无效或被停止）
    * @note 内部通过循环检查文件大小，每 1 毫秒重试一次，直到数据就绪或句柄失效
    */
   bool              WaitForRead(const ulong size);

   //--- 二进制写入接口（基础数据类型）
   /**
    * @brief 写入任意整数类型数据（模板函数，支持 char/short/int/uint/ushort 等）
    * @tparam T 整数类型（需为 POD 类型，如 char、int、uint 等）
    * @param value [in] 要写入的整数 value
    * @return uint - 实际写入的字节数：成功返回 sizeof(T)，失败返回 0
    */
   template<typename T>
   uint              WriteInteger(const T value);

   /**
    * @brief 写入 long/ulong 类型数据到文件/管道
    * @param value [in] 要写入的值（long 或 ulong 类型）
    * @return uint - 实际写入的字节数：成功返回 sizeof(long)（8字节），失败返回 0
    */
   uint              WriteLong(const long value);

   /**
    * @brief 写入 float 类型数据到文件/管道
    * @param value [in] 要写入的单精度浮点数（4字节）
    * @return uint - 实际写入的字节数：成功返回 sizeof(float)（4字节），失败返回 0
    */
   uint              WriteFloat(const float value);

   /**
    * @brief 写入 double 类型数据到文件/管道
    * @param value [in] 要写入的双精度浮点数（8字节）
    * @return uint - 实际写入的字节数：成功返回 sizeof(double)（8字节），失败返回 0
    */
   uint              WriteDouble(const double value);

   //--- 二进制写入接口（字符串）
   /**
    * @brief 写入完整字符串到文件/管道（自动附加字符串长度）
    * @param value [in] 要写入的字符串（支持 Unicode/ANSI，由 SetUnicode 控制）
    * @return uint - 实际写入的字节数：成功返回 sizeof(int) + 字符串字节数，失败返回 0
    * @note 存储格式：先写入 4 字节字符串长度（int 类型），再写入字符串内容
    */
   uint              WriteString(const string value);

   /**
    * @brief 写入指定长度的字符串片段到文件/管道（不附加长度）
    * @param value [in] 要写入的字符串（超出长度部分会被截断）
    * @param size [in] 要写入的字符数（不是字节数，每个字符占 1/2 字节，取决于编码）
    * @return uint - 实际写入的字节数：成功返回 size * 字符字节数，失败返回 0
    */
   uint              WriteString(const string value,const int size);

   //--- 二进制写入接口（通用模板，支持任意类型）
   /**
    * @brief 通用数组写入接口（模板函数，支持任意基础类型数组）
    * @tparam T 数组元素类型（如 int、double 等 POD 类型）
    * @param array [in] 要写入的数组（引用传递，需提前初始化）
    * @param start_item [in] 数组起始索引（默认 0，从第一个元素开始写入）
    * @param items_count [in] 要写入的元素个数（默认 WHOLE_ARRAY，写入整个数组）
    * @return uint - 实际写入的字节数：成功返回 元素个数 * sizeof(T)，失败返回 0
    */
   template<typename T>
   uint              WriteArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   /**
    * @brief 写入结构体到文件/管道（模板函数，支持任意 POD 结构体）
    * @tparam T 结构体类型（需为 POD 类型，不含指针、动态数组等复杂成员）
    * @param data [in] 要写入的结构体（引用传递，需提前初始化成员）
    * @return uint - 实际写入的字节数：成功返回 sizeof(T)，失败返回 0
    */
   template<typename T>
   uint              WriteStruct(T &data);

   /**
    * @brief 写入 CObject 派生对象到文件/管道（调用对象的 Save 方法）
    * @param object [in] 要写入的对象指针（需继承自 CObject，且实现 Save 方法）
    * @return bool - 操作结果：true 表示写入成功，false 表示失败（对象为空或 Save 失败）
    */
   bool              WriteObject(CObject *object);

   /**
    * @brief 写入枚举类型到文件/管道（自动转换为 int 存储）
    * @tparam T 枚举类型
    * @param value [in] 要写入的枚举值
    * @return uint - 实际写入的字节数：成功返回 sizeof(int)（4字节），失败返回 0
    */
   template<typename T>
   uint              WriteEnum(const T value) { return(WriteInteger((int)value)); }

   //--- 二进制读取接口（基础数据类型，带数据就绪等待）
   /**
    * @brief 读取任意整数类型数据（模板函数，自动等待数据就绪）
    * @tparam T 整数类型（需为 POD 类型，如 char、int、uint 等）
    * @param value [out] 读取结果存储变量（引用传递，接收整数 value）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败（等待超时或句柄无效）
    * @note 内部先调用 WaitForRead(sizeof(T)) 等待数据就绪，再执行读取
    */
   template<typename T>
   bool              ReadInteger(T &value);

   /**
    * @brief 读取 long/ulong 类型数据（自动等待数据就绪）
    * @param value [out] 读取结果存储变量（引用传递）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败
    * @note 内部先等待 8 字节数据就绪，再执行读取
    */
   bool              ReadLong(long &value);

   /**
    * @brief 读取 float 类型数据（自动等待数据就绪）
    * @param value [out] 读取结果存储变量（引用传递，接收单精度浮点数）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败
    * @note 内部先等待 4 字节数据就绪，再执行读取
    */
   bool              ReadFloat(float &value);

   /**
    * @brief 读取 double 类型数据（自动等待数据就绪）
    * @param value [out] 读取结果存储变量（引用传递，接收双精度浮点数）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败
    * @note 内部先等待 8 字节数据就绪，再执行读取
    */
   bool              ReadDouble(double &value);

   //--- 二进制读取接口（字符串，带数据就绪等待）
   /**
    * @brief 读取完整字符串（先读长度，再读内容，自动等待数据就绪）
    * @param value [out] 读取结果存储变量（引用传递，接收完整字符串）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败（长度/内容读取失败）
    * @note 读取流程：1. 等待 4 字节长度数据 → 2. 读取长度 → 3. 等待对应长度的字符串数据 → 4. 读取内容
    */
   bool              ReadString(string &value);

   /**
    * @brief 读取指定长度的字符串片段（自动等待数据就绪）
    * @param value [out] 读取结果存储变量（引用传递，接收字符串片段）
    * @param size [in] 要读取的字符数（不是字节数，取决于编码）
    * @return bool - 操作结果：true 表示读取成功（实际字符数等于 size），false 表示失败
    * @note 内部先等待 size 对应的字节数就绪，再执行读取
    */
   bool              ReadString(string &value,const int size);

   //--- 二进制读取接口（通用模板，带数据就绪等待）
   /**
    * @brief 通用数组读取接口（模板函数，自动等待数据就绪）
    * @tparam T 数组元素类型（如 int、double 等 POD 类型）
    * @param array [out] 读取结果存储数组（引用传递，需提前分配足够空间）
    * @param start_item [in] 数组起始索引（默认 0，从第一个元素开始存储）
    * @param items_count [in] 要读取的元素个数（默认 WHOLE_ARRAY，需确保数组空间足够）
    * @return uint - 实际读取的字节数：成功返回 元素个数 * sizeof(T)，失败返回 0
    * @note 内部先等待“元素个数 * sizeof(T)”字节数据就绪，再执行读取
    */
   template<typename T>
   uint              ReadArray(T &array[],const int start_item=0,const int items_count=WHOLE_ARRAY);

   /**
    * @brief 读取结构体（模板函数，自动等待数据就绪）
    * @tparam T 结构体类型（需为 POD 类型，不含指针、动态数组等复杂成员）
    * @param data [out] 读取结果存储结构体（引用传递，接收完整结构体数据）
    * @return uint - 实际读取的字节数：成功返回 sizeof(T)，失败返回 0
    * @note 内部先等待 sizeof(T) 字节数据就绪，再执行读取
    */
   template<typename T>
   uint              ReadStruct(T &data);

   /**
    * @brief 读取 CObject 派生对象（自动等待数据就绪，调用对象的 Load 方法）
    * @param object [in/out] 要读取的对象指针（需提前创建实例，调用其 Load 方法恢复数据）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败（对象为空或 Load 失败）
    * @note 内部先等待 4 字节数据就绪（对象数据的基础长度），再调用 Load 方法
    */
   bool              ReadObject(CObject *object);

   /**
    * @brief 读取枚举类型（从 int 转换为枚举，自动等待数据就绪）
    * @tparam T 枚举类型
    * @param value [out] 读取结果存储变量（引用传递，接收枚举值）
    * @return bool - 操作结果：true 表示读取成功，false 表示失败（int 读取失败或类型不匹配）
    * @note 内部先读取 int 类型数据，再强制转换为枚举类型
    */
   template<typename T>
   bool              ReadEnum(T &value);
  };
//+------------------------------------------------------------------+